#ifndef NctiWindowObject_H
#define NctiWindowObject_H
#include "ncti_dcl_window.h"
#include "ncti_base.h"
#include "ncti_event.h"
#include <vector>
#include <mutex>
#include "NctiVector.h"
struct GLFWwindow;
namespace NCTI
{
	class NctiWindowResizeEvent;
	class NctiWindowMouseEvent;
	class NctiWindowKeyEvent;
	class NctiWindowPlatform;
	class NctiWindowWheelEvent;
	class NctiWindowInputCharEvent;
	/**
	* @brief the base class of all window object
	* @see NctiUserInterfaceManager
	*/
	class DECL_NCTI_WINDOW NctiWindowObject
	{
	public:
		NctiWindowObject(NctiWindowObject* i_pParent,Ncti_Integer i_wid = 300,Ncti_Integer i_high = 300);
		virtual ~NctiWindowObject();
		/**
	   * @brief Initialization during load glfw model
	   */
        static Ncti_Boolean InitGlfw();

        /**
        * @brief set the parent handle of this
        * @param[in] i_handle, the window handle
        */
        void SetParent(Ncti_LongLong i_handle, NctiWindowObject* i_pParent = nullptr);

		/**
	   * @brief remove the child of window object
	   * @param[in] i_childe
	   */
        void RemoveChild(NctiWindowObject* i_childe);

        /**
        * @brief isVisible
        */
        Ncti_Boolean isVisible()const;

        /**
        * @brief pollEvents
        */
        void pollEvents();

		/**
	   * @brief display the window object
	   */
		void show();
		/**
	   * @brief hide the window object
	   */
		void hide();
		/**
	   * @brief set the window object title
	   * @param[in] i_pTitle
	   */
		void setWindowTitle(const Ncti_Char* i_pTitle);
		/**
	   * @brief set the window object geometry of width and height
	   * @param[in] i_x
	   * @param[in] i_y
	   * @param[in] i_w
	   * @param[in] i_h
	   */
		void setGeometry(
			Ncti_Integer i_x,
			Ncti_Integer i_y,
			Ncti_Integer i_w, 
			Ncti_Integer i_h);
		/**
	   * @brief get the window object geometry of width and height
	   * @param[out] o_x
	   * @param[out] o_y
	   * @param[out] o_w
	   * @param[out] o_h
	   */
		void GetGeometry(
			Ncti_Integer& o_x,
			Ncti_Integer& o_y,
			Ncti_Integer& o_w,
			Ncti_Integer& o_h);
		/**
	   * @brief hide the window object handle
	   * @return window handle
	   */
        Ncti_LongLong winId();
		/**
	   * @brief get mouse position of window object
	   * @param[out] o_x
	   * @param[out] o_y
	   */
		void GetMousePos(Ncti_Double& o_x, Ncti_Double& o_y);
		/**
	   * @brief get width of window object
	   * @return Ncti_Integer
	   */
		Ncti_Integer width() { return m_width; }
		/**
	   * @brief get height of window object
	   * @return Ncti_Integer
	   */
		Ncti_Integer height() { return m_height; }
		/**
	   * @brief set position by x y
	   * @param[in] i_x
	   * @param[in] i_y
	   */
		/**
	   * @brief move the position by vector
	   * @param[in] i_vec
	   */
		void MovePos(const NctiVector& i_vec);
		/**
	   * @brief get position x
	   * @return Ncti_Integer
	   */
		Ncti_Integer PosX() { return m_PosX; }
		/**
	   * @brief get position y
	   * @return Ncti_Integer
	   */
		Ncti_Integer PosY() { return m_PosY; }
		/**
	   * @brief set window object focus
	   */
		void setFocus();
		/**
	   * @brief determine whether window object is focus
	   * @return Ncti_Boolean
	   */
		Ncti_Boolean IsFocus();
		/**
	   * @brief set the window object maximize
	   */
		void MaximizeWindow();
		/**
	   * @brief get the window object title
	   */
		const Ncti_Char* Title() { return m_Title; }
		/**
	   * @brief close window object
	   */
		void Close();
	public:
		/**
	   * @brief set position function event
	   * @details need to implement, override
	   * @param[in] i_x
	   * @param[in] i_y
	   */
		virtual void posEvent(Ncti_Integer i_x, Ncti_Integer i_y){}
		/**
	   * @brief resize function event
	   * @details need to implement, override
	   * @param[in] i_event, NctiWindowResizeEvent
	   */
		virtual void resizeEvent(NctiWindowResizeEvent* i_event){}
		/**
	   * @brief key press function event
	   * @details need to implement, override
	   * @param[in] i_event, NctiWindowKeyEvent
	   */
		virtual void keyPressEvent(NctiWindowKeyEvent* i_event){}
		/**
	   * @brief key release function event
	   * @details need to implement, override
	   * @param[in] i_event, NctiWindowKeyEvent
	   */
		virtual void keyReleaseEvent(NctiWindowKeyEvent* i_event){}
		/**
	   * @brief key repeat function event
	   * @details need to implement, override
	   * @param[in] i_event, NctiWindowKeyEvent
	   */
		virtual void keyRepeatEvent(NctiWindowKeyEvent* i_event){}
		/**
	   * @brief mouse press function event
	   * @details need to implement, override
	   * @param[in] i_event, NctiWindowMouseEvent
	   */
		virtual void mousePressEvent(NctiWindowMouseEvent* i_event){}
		/**
	   * @brief mouse release function event
	   * @details need to implement, override
	   * @param[in] i_event, NctiWindowMouseEvent
	   */
		virtual void mouseReleaseEvent(NctiWindowMouseEvent* i_event){}
		/**
	   * @brief mouse move function event
	   * @details need to implement, override
	   * @param[in] i_event, NctiWindowMouseEvent
	   */
		virtual void mouseMoveEvent(NctiWindowMouseEvent* i_event){}
		/**
	   * @brief enter leave function event
	   * @details need to implement, override
	   * @param[in] i_enter
	   */
        virtual void enterLeaveEvent(Ncti_Boolean i_enter) {};
		/**
	   * @brief mouse double click function event
	   * @details need to implement, override
	   * @param[in] i_enter, NctiWindowMouseEvent
	   */
		virtual void mouseDoubleClickEvent(NctiWindowMouseEvent* i_event){}
		/**
	   * @brief wheel function event
	   * @details need to implement, override
	   * @param[in] i_enter, NctiWindowWheelEvent
	   */
		virtual void wheelEvent(NctiWindowWheelEvent* i_event){}
		/**
	   * @brief imput char function event
	   * @details need to implement, override
	   * @param[in] i_enter, NctiWindowInputCharEvent
	   */
		virtual void inputCharEvent(NctiWindowInputCharEvent* i_event){}
		/**
	   * @brief internal used
	   * @return Ncti_Boolean
	   */
		virtual Ncti_Boolean Wait();
    public:
		/**
		* @brief internal used
		*/
        void set_wh(Ncti_Integer i_w, Ncti_Integer i_h);
		/**
		* @brief internal used
		*/
        void set_pos(Ncti_Integer i_x, Ncti_Integer i_y);
		/**
		* @brief internal used
		*/
        void add_KeyboardCode(KeyboardCode i_KeyboardCode, Ncti_Integer i_keycode, ModifierKeys modKeys);
		/**
		* @brief internal used
		*/
        void remove_KeyboardCode(KeyboardCode i_KeyboardCode);
		/**
		* @brief internal used
		*/
        void set_MousePos(Ncti_Double i_x, Ncti_Double i_y);
		/**
		* @brief internal used
		*/
        Ncti_Boolean LastMouseClick(Ncti_Double i_x, Ncti_Double i_y, MouseButtons i_Buttons);
	private:
		/**
		* @brief internal used
		*/
		virtual void Onshow() {}
		/**
		* @brief internal used
		*/
		void CreateWindowHandle();
	protected:
		std::mutex m_mutex;
        Ncti_Char* m_Title;
        Ncti_Integer m_PosX;
        Ncti_Integer m_PosY;
        Ncti_Integer m_width;
        Ncti_Integer m_height;
        Ncti_Boolean m_isFullScreen;
        Ncti_Boolean m_visible;
        Ncti_Boolean m_OpenTransparent;
        Ncti_Boolean m_OpenFloating;
        Ncti_Boolean m_OpenTitle;
        Ncti_Boolean m_OpenMaximized;

        NctiWindowObject* m_Parent{ nullptr };
        std::vector<NctiWindowObject*> m_ChildVec;
        GLFWwindow* m_GLFWwindow{ nullptr };
    private:
        Ncti_Integer m_MousePosX;
        Ncti_Integer m_MousePosY;
        NctiWindowKeyEvent* m_pKeyEvent;
        NctiWindowMouseEvent* m_MouseEvent;
        Ncti_Double m_LastClickTime;
	};
}
#endif
